/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.giant.bean.transactions;

import com.giant.authentication.User;
import com.giant.bean.ReporteController;
import com.giant.entities.pos.PPos;
import com.giant.entities.InInventory;
import com.giant.entities.Person;
import com.giant.entities.TypeDealer;
import com.giant.entities.pos.PInvoice;
import com.giant.entities.pos.PInvoiceProd;
import com.giant.entities.pos.PInvoiceSeller;
import com.giant.exceptions.OperacionInvalidaException;
import com.giant.services.parametrics.ServiceCatalogLocal;
import com.giant.services.parametrics.ServiceInventoryLocal;
import com.giant.services.pos.ServiceInvoiceLocal;
import java.io.IOException;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Resource;
import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.transaction.UserTransaction;
import org.primefaces.model.StreamedContent;

/**
 *
 * @author Harold
 */
@ManagedBean
@SessionScoped
public class InvoiceAllBean implements Serializable {

    /**
     * Servicio de consulta de invoices
     */
    @EJB
    private ServiceInvoiceLocal serviceInvoice;
    /**
     * Servicio de consulta de inventario
     */
    @EJB
    private ServiceInventoryLocal serviceInventory;
    /**
     * Servicio de consulta de catalogos
     */
    @EJB
    private ServiceCatalogLocal serviceCatalag;
    /**
     * Atributo de transaccionalidad
     */
    @Resource
    UserTransaction utx;
    /**
     * Invoice temporal
     */
    private PInvoice invoice = new PInvoice();
    //-----------------------------------------------------------
    // Atributos
    //-----------------------------------------------------------
    private List<PInvoice> invoices;
    private User cashier;
    private User seller;
    private PPos pos;
    //products
    private List<PInvoiceProd> prods = new ArrayList<PInvoiceProd>();
    private PInvoiceProd tmpProd;
    private String tmpSku;
    private int tmpQuantityProd;
    private boolean noDealer = false;
    //filtros invoiceall
    private Date start;
    private Date finish;
    private String noInvoice = "";
    private TypeDealer typeDealer;
    private Person person;
    private boolean annulled = false;

    //-----------------------------------------------------------
    // Constructor
    //-----------------------------------------------------------
    public InvoiceAllBean() {
        //Traer el usuario que esta registrado
        ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
        Map<String, Object> sessionMap = externalContext.getSessionMap();
        cashier = (User) sessionMap.get("user");
        pos = (PPos) sessionMap.get("pos");
        //get current POS
        invoice.setIdPos(pos);
        //get current user - Cashier
        invoice.setIdCashier(cashier);
        //current date 
        invoice.setDateInvoice(new java.util.Date());
    }

    //-----------------------------------------------------------
    // Getters y setters
    //-----------------------------------------------------------
    public PInvoice getInvoice() {
        return invoice;
    }

    public void setInvoice(PInvoice invoice) {
        this.invoice = invoice;
    }

    public User getSeller() {
        return seller;
    }

    public void setSeller(User seller) {
        this.seller = seller;
    }

    public boolean isAnnulled() {
        return annulled;
    }

    public void setAnnulled(boolean annulled) {
        this.annulled = annulled;
    }

    public PInvoiceProd getTempProd() {
        return tmpProd;
    }

    public void setTempProd(PInvoiceProd tempProd) {
        this.tmpProd = tempProd;
    }

    public String getTmpSku() {
        return tmpSku;
    }

    public void setTmpSku(String tmpSku) {
        this.tmpSku = tmpSku;
    }

    public int getTmpQuantityProd() {
        return tmpQuantityProd;
    }

    public void setTmpQuantityProd(int tmpQuantityProd) {
        this.tmpQuantityProd = tmpQuantityProd;
    }

    public List<PInvoiceProd> getProds() {
        return prods;
    }

    public void setProds(List<PInvoiceProd> prods) {
        this.prods = prods;
    }

    public String getParameter() {

        PInvoice tmp = serviceInvoice.getLastInvoice();
        int lastInvoice = tmp.getIdInvoice();
        //System.out.println("lastinvoice:" + lastInvoice);
        return "id_invoice=" + lastInvoice;
    }

    /**
     * Devuelve todos los vendedores del sistema
     *
     * @return vendedores Lista con todos los vendedores del sistema
     */
    public List<PInvoice> getInvoices() {
        if (invoices == null) {
            invoices = serviceInvoice.getInvoices();
        }
        return invoices;
    }

    public boolean isIsDealer() {
        return noDealer;
    }

    public void setIsDealer(boolean isDealer) {
        this.noDealer = isDealer;
    }

    public Date getStart() {
        return start;
    }

    public void setStart(Date start) {
        this.start = start;
    }

    public Date getFinish() {
        return finish;
    }

    public void setFinish(Date finish) {
        this.finish = finish;
    }

    public String getNoInvoice() {
        return noInvoice;
    }

    public void setNoInvoice(String noInvoice) {
        this.noInvoice = noInvoice;
    }

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    public TypeDealer getTypeDealer() {
        return typeDealer;
    }

    public void setTypeDealer(TypeDealer typeDealer) {
        this.typeDealer = typeDealer;
    }

    //-----------------------------------------------------------
    // Methods
    //-----------------------------------------------------------
    /**
     * Save one invoice an all of his parts
     *
     * @return
     */
    public StreamedContent saveInvoice() {
        System.out.println("saveInvoice");
        //String ret = "";
        StreamedContent file = null;
        try {

            //TODO save payments

            //Save invoice seller
            PInvoiceSeller invoiceSeller = new PInvoiceSeller();
            invoiceSeller.setIdInvoice(invoice);
            invoiceSeller.setIdSeller(seller);

            //saving invoice, prods, seller, taxes
            serviceInvoice.addInvoice(invoice, prods, invoiceSeller);
            FacesContext context = FacesContext.getCurrentInstance();
            context.addMessage(null, new FacesMessage("Save Successful!", "Save Invoice"));
            context.getExternalContext().getSessionMap().put("invoiceAllBean", null);

            //generate jasper
            ReporteController rc = new ReporteController();
            file = rc.getFile("invoice_fatura", getParameter(), "invoice_mod", "Invoice");

        } catch (OperacionInvalidaException ex) {
            Logger.getLogger(PInvoice.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(InvoiceAllBean.class.getName()).log(Level.SEVERE, null, ex);
        }

        return file;
    }

    /**
     * add detail prod to invoice
     */
    public void addProductToInvoice() {
        //id person may have to be selected before add prods
        if (invoice.getIdPerson() == null) {
            FacesContext context = FacesContext.getCurrentInstance();
            context.addMessage(null, new FacesMessage("You have to select first the customer"));
            return;
        }
        // 0 is not a valid quantity
        if (tmpQuantityProd == 0) {
            FacesContext context = FacesContext.getCurrentInstance();
            context.addMessage(null, new FacesMessage("0 is not a valid quantity!"));
            return;
        }

        //TODO validate fields
        //TODO CHECK warehouse and pos localization

        Map<String, String> map = new HashMap<String, String>();
        map.put("sku", tmpSku);
        List<InInventory> inventories = serviceInventory.getInventoryFilter("InInventory.findBySkuStatusInProcess", map);
        System.out.println("inventories-->" + inventories.size());
        //validate quantity
        //TODO Validate sku or make an autocomple por sku
        if (inventories.size() < tmpQuantityProd) {
            FacesContext context = FacesContext.getCurrentInstance();
            context.addMessage(null, new FacesMessage("The quantity for that product exceeds the inventory quantity!"));
            return;
        }
        float taxValue = 0;
        float totalValue = 0;
        float grossValue = 0;
        for (int i = 0; i < tmpQuantityProd; i++) {
            tmpProd = new PInvoiceProd();
            tmpProd.setIdInvoice(invoice);
            tmpProd.setIdInventory(inventories.get(i));

            //block's in_inventory_dv with column in_process 1
            inventories.get(i).setInProcess(true);
            serviceInventory.updateInventory(inventories.get(i));

            //check's if id_person is retail or dealer to set's the product price
            //if dealer price
            if (invoice.getIdPerson().getDealer()) {
                totalValue = inventories.get(i).getSalePrice();
            } //if retail price
            else {
                totalValue = inventories.get(i).getRetailPrice();
            }

            //tax calc.
            grossValue = (float) (Math.rint(((totalValue * 100) / (inventories.get(i).getIdCatalog().getTaxPer().getTaxPer() + 100)) * 100) / 100);
            taxValue = (float) (Math.rint((totalValue - grossValue) * 100) / 100);

            //set values to tmp invoice product
            tmpProd.setTotalValue(totalValue);
            tmpProd.setGrossValue(grossValue);
            tmpProd.setUnitValue(grossValue);
            tmpProd.setTaxValue(taxValue);
            tmpProd.setIdTypeTax(inventories.get(i).getIdCatalog().getTaxPer());

            //add tmpProd to temp list of products
            prods.add(tmpProd);

            //update totals invoice
            updateTotals();

        }

        setTmpSku("");
        setTmpQuantityProd(0);

    }

    /**
     * Update discount to invoice details and total invoice head
     *
     * @param prod
     */
    public void updateDiscount(PInvoiceProd prod) {
        float newTotalValue = 0, newTaxValue = 0, newGrossValue = 0;

        newTotalValue = (float) (Math.rint((prod.getTotalValue() - (prod.getTotalValue() * (prod.getDiscountPercentage() / 100))) * 100) / 100);
        prod.setTotalValue(newTotalValue);

        newTaxValue = (float) (Math.rint((prod.getTaxValue() - (prod.getTaxValue() * (prod.getDiscountPercentage() / 100))) * 100) / 100);
        prod.setTaxValue(newTaxValue);

        newGrossValue = (float) (Math.rint((prod.getGrossValue() - (prod.getGrossValue() * (prod.getDiscountPercentage() / 100))) * 100) / 100);
        prod.setGrossValue(newGrossValue);

        updateTotals();

    }

    /**
     * Update´s totals invoice head
     */
    private void updateTotals() {

        float tot = 0, tax = 0, gross = 0;

        for (int i = 0; i < prods.size(); i++) {
            PInvoiceProd prod = prods.get(i);
            tot += prod.getTotalValue();
            tax += prod.getTaxValue();
            gross += prod.getGrossValue();
        }

        tot = (float) (Math.rint(tot * 100) / 100);
        tax = (float) (Math.rint(tax * 100) / 100);
        gross = (float) (Math.rint(gross * 100) / 100);
        invoice.setTotalValue(tot);
        invoice.setTaxValue(tax);
        invoice.setGrossValue(gross);
    }

    public void filterCriteria() {
        String sql = "SELECT i FROM PInvoice i where 1=1";

        if (noInvoice != null && !noInvoice.equals("")) {
            sql += " and i.invoiceNumber=" + noInvoice;
        }

        if (person != null && !person.equals("")) {
            sql += " and i.idPerson.idPerson=" + person.getIdPerson();
        }

        if (typeDealer != null && !typeDealer.equals("")) {
            sql += " and i.idPerson.idTypeDealer.idTypeDealer=" + typeDealer.getIdTypeDealer();
        }

        if(!annulled)
        {
            sql += " and i.annuled=0";
        }


        if (start != null && finish != null) {

            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            String dateIni = format.format(start);
            String dateFin = format.format(finish);

            sql += " and i.dateInvoice between {d '" + dateIni + "'} and {d '" + dateFin + "'}";

        }
        System.out.println(sql);
        invoices = serviceInvoice.getInvoicesFilterSql(sql);
    }

    /**
     * Print a PDF invoice
     *
     * @param inv
     * @return
     */
    public StreamedContent printJasper(PInvoice inv) {
        System.out.println("print jasper" + inv.getIdInvoice());

        StreamedContent file = null;
        String parameter = "id_invoice=" + inv.getIdInvoice();
        ReporteController rc;
        try {
            rc = new ReporteController();
            file = rc.getFile("invoice_fatura", parameter, "invoice_mod", "Invoice");
        } catch (IOException ex) {
            Logger.getLogger(InvoiceAllBean.class.getName()).log(Level.SEVERE, null, ex);
        }

        return file;
    }

    /**
     * Clear all fields from invoice
     */
    public void clearInvoice() {
        for (int i = 0; i < prods.size(); i++) {
            InInventory inv = prods.get(i).getIdInventory();
            inv.setInProcess(false);
            serviceInventory.updateInventory(inv);
        }
        FacesContext context = FacesContext.getCurrentInstance();
        context.getExternalContext().getSessionMap().put("invoiceAllBean", null);
    }

    /**
     * Remove a invoice detail
     *
     * @param invoiceProd
     */
    public void removeInvoiceProd(PInvoiceProd invoiceProd) {
        boolean termino = false;
        for (int i = 0; i < prods.size() && termino == false; i++) {
            PInvoiceProd prTmp = prods.get(i);
            if (prTmp.getIdInventory().getSku().equals(invoiceProd.getIdInventory().getSku())) {
                prods.remove(i);
                termino = true;
            }
        }
        updateTotals();
    }

    public void annulInvoice(PInvoice inv) {
        System.out.println("annul invoice");
        inv.setAnnuled(true);
        inv.setDateAnnu(new java.util.Date());
        //TODO hard coded comment
        inv.setReasonAnnu("Invoice annul by request");
        inv.setIdUserAnnu(cashier);
        serviceInvoice.annulInvoice(inv);


    }
}
